﻿using System;
using System.IO;
using System.Windows.Forms;
using System.Xml.Serialization;
using CalcSharp.Core;

namespace CalcSharp.MDIUI.Dialogs
{
    /// <summary>
    /// Creates a convoluton matrix editor dialog
    /// </summary>
    public partial class ConvolutionEditor : Form
    {
        public ConvolutionEditor()
        {
            InitializeComponent();
        }

        private void SwitchMatrixType(bool use5x5)
        {
            this.R0C0.Visible = use5x5;
            this.R0C1.Visible = use5x5;
            this.R0C2.Visible = use5x5;
            this.R0C3.Visible = use5x5;
            this.R0C4.Visible = use5x5;
            this.R1C0.Visible = use5x5;
            this.R1C4.Visible = use5x5;
            this.R2C0.Visible = use5x5;
            this.R2C4.Visible = use5x5;
            this.R3C0.Visible = use5x5;
            this.R3C4.Visible = use5x5;
            this.R4C0.Visible = use5x5;
            this.R4C1.Visible = use5x5;
            this.R4C2.Visible = use5x5;
            this.R4C3.Visible = use5x5;
            this.R4C4.Visible = use5x5;
        }

        private void Rb3x3_Click(object sender, EventArgs e)
        {
            if (Rb3x3.Checked) this.SwitchMatrixType(false);
            else this.SwitchMatrixType(true);
        }

        private void Rb5x5_Click(object sender, EventArgs e)
        {
            if (Rb5x5.Checked) this.SwitchMatrixType(true);
            else this.SwitchMatrixType(false);
        }

        private void saveToFileToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (SavePreset.ShowDialog() == DialogResult.OK)
            {
                if (SavePreset.FilterIndex == 0)
                {
                    try
                    {
                        FileStream outp = File.Create(SavePreset.FileName);
                        XmlSerializer xs = new XmlSerializer(typeof(short[,]));
                        xs.Serialize(outp, this.ConvMatrix);
                        outp.Close();
                    }
                    catch (Exception)
                    {
                        MessageBox.Show("Error while saving file", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    }
                }
                else
                {
                    bool restore = false;
                    if (Rb3x3.Checked)
                    {
                        restore = true;
                        Rb3x3.Checked = false;
                        Rb5x5.Checked = true;
                    }
                    short[] data = new short[27];
                    int i, j, k = 0;
                    for (i = 0; i < this.ConvMatrix.GetLength(0); i++)
                    {
                        for (j = 0; j < this.ConvMatrix.GetLength(1); j++)
                        {
                            data[k] = this.ConvMatrix[i, j];
                            k++;
                        }
                    }
                    data[25] = this.Factor;
                    data[26] = this.Offset;
                    FileStream outp = File.Create(SavePreset.FileName);
                    BinaryWriter bw = new BinaryWriter(outp);
                    byte[] tmp;
                    for (i = 0; i < data.Length; i++)
                    {
                        tmp = BitConverter.GetBytes(data[i]);
                        Array.Reverse(tmp);
                        bw.Write(tmp);
                    }
                    bw.Close();
                    if (restore)
                    {
                        Rb5x5.Checked = false;
                        Rb3x3.Checked = true;
                    }
                }
            }
        }

        private void loadFromFileToolStripMenuItem_Click(object sender, EventArgs e)
        {
            FileStream inp;
            if (OpenPreset.ShowDialog() == DialogResult.OK)
            {
                if (OpenPreset.FileName.ToUpper().EndsWith(".XML"))
                {
                    try
                    {
                        inp = File.OpenRead(OpenPreset.FileName);
                        XmlSerializer xs = new XmlSerializer(typeof(short[,]));
                        short[,] tmp = (short[,])xs.Deserialize(inp);
                        inp.Close();
                        if (tmp.Length != 9 && tmp.Length != 25) throw new Exception("Element count mismatch");
                        this.ConvMatrix = tmp;
                    }
                    catch (Exception)
                    {
                        MessageBox.Show("Error while loading file", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    }
                }
                else
                {
                    try
                    {
                        inp = File.OpenRead(OpenPreset.FileName);
                        BinaryReader br = new BinaryReader(inp);
                        if (inp.Length != 54) throw new CSException();
                        Rb3x3.Checked = false;
                        Rb5x5.Checked = true;
                        byte[] buffr;
                        short[,] mtrx = new short[5, 5];
                        for (int i = 0; i < 5; i++)
                        {
                            for (int j = 0; j < 5; j++)
                            {
                                buffr = br.ReadBytes(2);
                                Array.Reverse(buffr);
                                mtrx[i, j] = BitConverter.ToInt16(buffr, 0); 
                            }
                        }
                        buffr = br.ReadBytes(2);
                        Array.Reverse(buffr);
                        this.Factor = BitConverter.ToInt16(buffr, 0);
                        buffr = br.ReadBytes(2);
                        Array.Reverse(buffr);
                        this.Offset = BitConverter.ToInt16(buffr, 0);
                        this.ConvMatrix = mtrx;
                        br.Close();
                    }
                    catch (Exception)
                    {
                        MessageBox.Show("Error while loading file", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    }
                }
            }
        }

        private void PresetLoad(object sender, EventArgs e)
        {
            ToolStripMenuItem s = (ToolStripMenuItem)sender;
            switch (s.Name)
            {
                case "MBlur":
                    this.LoadConvPreset(ConvolutonPresets.Blur);
                    break;
                case "MGausian":
                    this.LoadConvPreset(ConvolutonPresets.GausianBlur);
                    break;
                case "MSharpen":
                    this.LoadConvPreset(ConvolutonPresets.Sharpen1);
                    break;
                case "MSharpenMore":
                    this.LoadConvPreset(ConvolutonPresets.Sharpen2);
                    break;
                case "MMeanRemoval":
                    this.LoadConvPreset(ConvolutonPresets.MeanRemoval);
                    break;
            }
        }

        /// <summary>
        /// Gets or sets the convolution matrix
        /// </summary>

        public short[,] ConvMatrix
        {
            get
            {
                if (Rb3x3.Checked)
                {
                    short[,] ret = new short[3, 3];
                    ret[0, 0] = (short)this.R0C1.Value;
                    ret[0, 1] = (short)this.R0C2.Value;
                    ret[0, 2] = (short)this.R0C3.Value;
                    ret[1, 0] = (short)this.R1C1.Value;
                    ret[1, 1] = (short)this.R1C2.Value;
                    ret[1, 2] = (short)this.R1C3.Value;
                    ret[2, 0] = (short)this.R2C1.Value;
                    ret[2, 1] = (short)this.R2C2.Value;
                    ret[2, 2] = (short)this.R2C3.Value;
                    return ret;
                }
                else
                {
                    short[,] ret = new short[5, 5];
                    ret[0, 0] = (short)this.R0C0.Value;
                    ret[0, 1] = (short)this.R0C1.Value;
                    ret[0, 2] = (short)this.R0C2.Value;
                    ret[0, 3] = (short)this.R0C3.Value;
                    ret[0, 4] = (short)this.R0C4.Value;
                    ret[1, 0] = (short)this.R1C0.Value;
                    ret[1, 1] = (short)this.R1C1.Value;
                    ret[1, 2] = (short)this.R1C2.Value;
                    ret[1, 3] = (short)this.R1C3.Value;
                    ret[1, 4] = (short)this.R1C4.Value;
                    ret[2, 0] = (short)this.R2C0.Value;
                    ret[2, 1] = (short)this.R2C1.Value;
                    ret[2, 2] = (short)this.R2C2.Value;
                    ret[2, 3] = (short)this.R2C3.Value;
                    ret[2, 4] = (short)this.R2C4.Value;
                    ret[3, 0] = (short)this.R3C0.Value;
                    ret[3, 1] = (short)this.R3C1.Value;
                    ret[3, 2] = (short)this.R3C2.Value;
                    ret[3, 3] = (short)this.R3C3.Value;
                    ret[3, 4] = (short)this.R3C4.Value;
                    ret[4, 0] = (short)this.R4C0.Value;
                    ret[4, 1] = (short)this.R4C1.Value;
                    ret[4, 2] = (short)this.R4C2.Value;
                    ret[4, 3] = (short)this.R4C3.Value;
                    ret[4, 4] = (short)this.R4C4.Value;
                    return ret;
                }
            }
            set
            {
                if (value.GetLength(0) == 3 && value.GetLength(1) == 3)
                {
                    this.R1C1.Value = value[0, 0];
                    this.R1C2.Value = value[0, 1];
                    this.R1C3.Value = value[0, 2];
                    this.R2C1.Value = value[1, 0];
                    this.R2C2.Value = value[1, 1];
                    this.R2C3.Value = value[1, 2];
                    this.R3C1.Value = value[2, 0];
                    this.R3C2.Value = value[2, 1];
                    this.R3C3.Value = value[2, 2];
                    this.SwitchMatrixType(false);
                }
                else
                {
                    this.R0C0.Value = value[0, 0];
                    this.R0C1.Value = value[0, 1];
                    this.R0C2.Value = value[0, 2];
                    this.R0C3.Value = value[0, 3];
                    this.R0C4.Value = value[0, 4];
                    this.R1C0.Value = value[1, 0];
                    this.R1C1.Value = value[1, 1];
                    this.R1C2.Value = value[1, 2];
                    this.R1C3.Value = value[1, 3];
                    this.R1C4.Value = value[1, 4];
                    this.R2C0.Value = value[2, 0];
                    this.R2C1.Value = value[2, 1];
                    this.R2C2.Value = value[2, 2];
                    this.R2C3.Value = value[2, 3];
                    this.R2C4.Value = value[2, 4];
                    this.R3C0.Value = value[3, 0];
                    this.R3C1.Value = value[3, 1];
                    this.R3C2.Value = value[3, 2];
                    this.R3C3.Value = value[3, 3];
                    this.R3C4.Value = value[3, 4];
                    this.R4C0.Value = value[4, 0];
                    this.R4C1.Value = value[4, 1];
                    this.R4C2.Value = value[4, 2];
                    this.R4C3.Value = value[4, 3];
                    this.R4C4.Value = value[4, 4];
                    this.SwitchMatrixType(true);
                }
            }
        }

        /// <summary>
        /// Loads a convoluton preset
        /// </summary>
        /// <param name="p">The preset to be loaded</param>
        public void LoadConvPreset(ConvolutionPreset p)
        {
            this.ConvMatrix = p.ConvMatrix;
            this.Factor = p.Factor;
            this.Offset = p.Offset;
        }

        /// <summary>
        /// Gets or sets the factor
        /// </summary>
        public short Factor
        {
            get { return (short)NFactor.Value; }
            set { this.NFactor.Value = value; }
        }

        /// <summary>
        /// gets or sets the offset
        /// </summary>
        public short Offset
        {
            get { return (short)NOffset.Value; }
            set { this.NOffset.Value = value; }
        }
    }
}
